IU Tips

Archicadの設定をgitで管理する マークダウン書出編【Archicad】【Python】

2024.06.14

こんにちは。IU BIM STUDIOの原田です。

Archicadでモデルを作る際にテンプレートを利用しますが、BIMソフトの設定はとにかく数が多いため、テンプレートのどの部分を変えたかを管理することはなかなか難しいです。

更新の前の状態を残しておかないと何が変わったかわからないし、何でそう変えたのかも忘れてしまっている…

そういう問題への対処方法の一つとして、テキストファイルとgitで管理する方法があると思いますので試してみたいと思います。

gitとは

gitとは、ソフトウェア開発でよく使われるバージョン管理ソフトです。
基本的にはテキストファイルを管理することができ、
管理対象のファイルを前の状態に戻したり、別バージョンを同時に管理したりすることができます。

マークダウンファイルで情報を出力

今回はビルディングマテリアルの設定をマークダウンファイルに書き出してみたいと思います。

マークダウンファイルというのは文章を見やすくするための記法を使ったテキストファイルで、対応しているアプリを使うと整形して表示してくれます。ブログなどを書いたことがある方は使ったことがあるかもしれません。

https://ja.wikipedia.org/wiki/Markdown

実際、マークダウンを使うのがベストかはわかりませんが、管理方法を決めるときには
・作りやすさ
・非エンジニアユーザーにとってのわかりやすさ
・データの視認性
などを考えて選ぶ必要があるかなと思います。
とりあえず今回はマークダウンでやってみたいと思います。

ビルディングマテリアルをマークダウンで書き出す

最終的に欲しいのはビルディングマテリアルの情報ですが、ビルディングマテリアルで使われている塗りつぶしと材質の情報はPython APIからビルディングマテリアルを取得した場合、GUIDでしか取得できません。

GUIDを見ても人間にはわからないので、塗りつぶしと材質の情報を先に取得してGUIDから名前を検索できる辞書を作っておきます。

def create_fill_dict() -> dict:
    attributes = acc.GetAttributesByType("Fill")
    fills = acc.GetFillAttributes(attributes)
    fill_dict = {}

    for fill in fills:
        guid = str(fill.fillAttribute.attributeId.guid)
        name = fill.fillAttribute.name

        fill_dict[guid] = name

    return fill_dict

def create_surface_dict() -> dict:
    attributes = acc.GetAttributesByType("Surface")
    surfaces = acc.GetSurfaceAttributes(attributes)
    surface_dict = {}

    for surface in surfaces:
        guid = str(surface.surfaceAttribute.attributeId.guid)
        name = surface.surfaceAttribute.name

        surface_dict[guid] = name

    return surface_dict

次にpandasを使って取得した情報を整理します。
pandasはデータ分析などによく使われるpythonのライブラリですが、特に必須ではありません。

# ビルディングマテリアル設定をDataFrameに変換
def builing_material_to_df(fill_dict: dict, surface_dict: dict) -> pd.DataFrame:
    # ビルディングマテリアルのIDを取得
    attributes = acc.GetAttributesByType("BuildingMaterial")
    building_materials = acc.GetBuildingMaterialAttributes(attributes)

    # 各ビルディングマテリアルの設定を取得
    settings = []
    for building_material in building_materials:
        attribute_data = building_material.buildingMaterialAttribute
        name = attribute_data.name
        guid = str(attribute_data.attributeId.guid)
        id = attribute_data.id
        priority = attribute_data.connectionPriority

        cut_fill_id = str(attribute_data.cutFillId.attributeId.guid)
        cut_fill = fill_dict[cut_fill_id]

        cut_fill_pen = attribute_data.cutFillPenIndex

        cut_surface_id = str(attribute_data.cutSurfaceId.attributeId.guid)
        cut_surface = surface_dict[cut_surface_id]

        settings.append([name, guid, id, priority, cut_fill, cut_fill_pen, cut_surface])

    df = pd.DataFrame(
        settings,
        columns=[
            "名前",
            "GUID",
            "ID",
            "優先度",
            "切断塗りつぶし",
            "切断塗りつぶし前景ペン",
            "材質",
        ],
    )

    return df

基本的には各ビルディングマテリアルの設定をリストに入れていくだけですが、「切断塗りつぶし」と「材質」はGUIDをキーにして名前をリストに入れます。

そして途中で気づいたのですが、切断塗りつぶし背景ペンはAPIから取得できないようです…
Python APIで取得できない設定はちょいちょいあるので、この辺りは改善してほしいところです。

dataframeを作成したら格納したデータをマークダウン形式に変換します

def row_to_table(data: list) -> str:
    # マークダウン記法を適用"|"で各列を区切る
    text = "|"
    for item in data:
        text += str(item)
        text += "|"
    text += "\n"
    return text

def header_to_table(header: list) -> list[str]:
    """マークダウン記法のヘッダを記入
    list = ["a","b","c"]

    |a|b|c|
    |----|----|----|
    """
    text_content = []
    text_content.append(row_to_table(header))

    text = "|"
    for _ in range(len(header)):
        text += "----|"

    text += "\n"

    text_content.append(text)

    return text_content

# dfをマークダウン記法のテキストに変換
def df_to_text(df: pd.DataFrame) -> list[str]:
    text_content = []

    text_content.extend(header_to_table(df.columns.values))

    for row in df.iterrows():
        text_content.append(row_to_table(row[1].values))

    return text_content

マークダウンの表形式で設定を書き出していきます。
マークダウンで表を作るには各列の間を|(バーティカルバー)で区切る必要があります。
また、見出し行も欲しいので、それらを書き出すための関数を作成します。

作成されたファイルを確認する

pythonスクリプトを実行すると下記のようなテキストが作成されました。

情報はきちんと出ているようですが、このままでは少し見にくいのでVSCodeの拡張機能を使ってみると、下記のように整えられた状態で見ることができます。

今回使った拡張機能は下記のものです。
https://marketplace.visualstudio.com/items?itemName=searKing.preview-vscode
ブラウザでも拡張機能を使えば、見た目を整えることが可能です。

これで、マークダウンの書き出しは完了です。

次回、gitを使ったファイル管理にトライしてみようと思います。

最後までお読みいただきありがとうございました。
以下にコード全文を載せておきます。

import pandas as pd
from archicad import ACConnection

conn = ACConnection.connect()

acc = conn.commands
act = conn.types
acu = conn.utilities


def create_fill_dict() -> dict:
    attributes = acc.GetAttributesByType("Fill")
    fills = acc.GetFillAttributes(attributes)
    fill_dict = {}

    for fill in fills:
        guid = str(fill.fillAttribute.attributeId.guid)
        name = fill.fillAttribute.name

        fill_dict[guid] = name

    return fill_dict


def create_surface_dict() -> dict:
    attributes = acc.GetAttributesByType("Surface")
    surfaces = acc.GetSurfaceAttributes(attributes)
    surface_dict = {}

    for surface in surfaces:
        guid = str(surface.surfaceAttribute.attributeId.guid)
        name = surface.surfaceAttribute.name

        surface_dict[guid] = name

    return surface_dict


# ビルディングマテリアル設定をDataFrameに変換
def builing_material_to_df(fill_dict: dict, surface_dict: dict) -> pd.DataFrame:
    # ビルディングマテリアルのIDを取得
    attributes = acc.GetAttributesByType("BuildingMaterial")
    building_materials = acc.GetBuildingMaterialAttributes(attributes)

    # 各ビルディングマテリアルの設定を取得
    settings = []
    for building_material in building_materials:
        attribute_data = building_material.buildingMaterialAttribute
        name = attribute_data.name
        guid = str(attribute_data.attributeId.guid)
        id = attribute_data.id
        priority = attribute_data.connectionPriority

        cut_fill_id = str(attribute_data.cutFillId.attributeId.guid)
        cut_fill = fill_dict[cut_fill_id]

        cut_fill_pen = attribute_data.cutFillPenIndex

        cut_surface_id = str(attribute_data.cutSurfaceId.attributeId.guid)
        cut_surface = surface_dict[cut_surface_id]

        settings.append([name, guid, id, priority, cut_fill, cut_fill_pen, cut_surface])

    df = pd.DataFrame(
        settings,
        columns=[
            "名前",
            "GUID",
            "ID",
            "優先度",
            "切断塗りつぶし",
            "切断塗りつぶし前景ペン",
            "材質",
        ],
    )

    return df


def row_to_table(data: list) -> str:
    # マークダウン記法を適用"|"で各列を区切る
    text = "|"
    for item in data:
        text += str(item)
        text += "|"
    text += "\n"
    return text


def header_to_table(header: list) -> list[str]:
    """マークダウン記法のヘッダを記入
    list = ["a","b","c"]

    |a|b|c|
    |----|----|----|
    """
    text_content = []
    text_content.append(row_to_table(header))

    text = "|"
    for _ in range(len(header)):
        text += "----|"

    text += "\n"

    text_content.append(text)

    return text_content


# dfをマークダウン記法のテキストに変換
def df_to_md(df: pd.DataFrame) -> list[str]:
    text_content = []

    text_content.extend(header_to_table(df.columns.values))

    for row in df.iterrows():
        text_content.append(row_to_table(row[1].values))

    return text_content


# mdファイルを保存
def save_text_as_md(text_content: list[str], file_name: str) -> None:
    with open(file_name, "w", encoding="utf-8") as f:
        f.writelines(text_content)


def main():
    fill_dict = create_fill_dict()
    surface_dict = create_surface_dict()
    df = builing_material_to_df(fill_dict, surface_dict)
    text = df_to_md(df)
    save_text_as_md(text, "building_material.md")


if __name__ == "__main__":
    main()